package cn.kys.common.utils;

import java.util.ArrayList;
import java.util.List;

/**
 *
 */
public class EYTools {
    /**
     * 获取主要界址点
     * @param jzds 原始的界址点坐标
     * @return
     */
    public static List<String> getMainjzd(List<String> jzds)
    {
        List<String> values = new ArrayList<String>();
        //values = getMainjzdbySZ(jzds);//划分宗地四至的点
        values = getMainjzdbyBound(jzds);//包含坐标极值的点
        return values;
    }
    /**
     * 获取主要界址点（包含坐标极值的点）
     * @param jzds 原始的界址点坐标
     * @return
     */
    public static List<String> getMainjzdbyBound(List<String> jzds)
    {
        Double[] bound=new Double[4];//外接矩形左下点和右上点坐标
        List<String> values=new ArrayList<String>();
        vector[] jzdzb=new vector[jzds.size()];
        int[] jzdindex=new int[4];
        int jzdcount=jzds.size();
        for (int i=0;i<jzdcount;i++) {
            String[] lonlat=jzds.get(i).split(" ");
            jzdzb[i]=new vector(Double.valueOf(lonlat[0]),Double.valueOf(lonlat[1]));
            if(i==0)
            {
                bound[0]=jzdzb[i].x;
                bound[1]=jzdzb[i].y;
                bound[2]=jzdzb[i].x;
                bound[3]=jzdzb[i].y;
            }
            else{
                if(jzdzb[i].x<bound[0]) {
                    bound[0] = jzdzb[i].x;
                    jzdindex[0]=i;
                }
                else if(jzdzb[i].x>bound[2]) {
                    bound[2] = jzdzb[i].x;
                    jzdindex[2]=i;
                }
                if(jzdzb[i].y<bound[1]) {
                    bound[1] = jzdzb[i].y;
                    jzdindex[1]=i;
                }
                else if(jzdzb[i].y>bound[3]) {
                    bound[3] = jzdzb[i].y;
                    jzdindex[3]=i;
                }
            }
        }
        for(int j : jzdindex)
        {
            StringBuilder zb=new StringBuilder();
            zb.append(jzdzb[j].x.toString()+" "+jzdzb[j].y.toString());
            values.add(zb.toString());
        }
        return values;
    }
    /**
     * 获取主要界址点（划分宗地四至的点）
     * @param jzds 原始的界址点坐标
     * @return
     */
    public static List<String> getMainjzdbySZ(List<String> jzds)
    {
        List<String> values=new ArrayList<String>();
        vector[] jzdzb=new vector[jzds.size()];
        int jzdcount=jzds.size();
        for (int i=0;i<jzdcount;i++) {
            String[] lonlat=jzds.get(i).split(" ");
            jzdzb[i]=new vector(Double.valueOf(lonlat[0]),Double.valueOf(lonlat[1]));
        }
        int[] jzdindex=getSZJDindex(jzdzb);
        for(int j : jzdindex)
        {
            StringBuilder zb=new StringBuilder();
            zb.append(jzdzb[j].x.toString()+" "+jzdzb[j].y.toString());
            values.add(zb.toString());
        }
        return values;
    }
    public static class vector
    {
        public Double x;
        public Double y;
        public vector(Double x,Double y)
        {
            this.x=x;
            this.y=y;
        }
    }
    /**
     * 获取主要界址点
     * @param jzds 原始的界址点坐标
     * @return
     */
    public static List<String> getMainjzdbyDrop(List<String> jzds)
    {
        Double jlblrc = 0.3;//距离比例容差
        Double[] bound=new Double[4];//外接矩形左下点和右上点坐标
        List<String> values=new ArrayList<String>();
        Double[] jzdzb=new Double[jzds.size()*2];
        int jzdcount=jzds.size();
        for (int i=0;i<jzds.size();i++) {
            String[] lonlat=jzds.get(i).split(" ");
            jzdzb[i*2]=Double.valueOf(lonlat[0]);
            jzdzb[i*2+1]=Double.valueOf(lonlat[1]);
            if(i==0)
            {
                bound[0]=jzdzb[i*2];
                bound[1]=jzdzb[i*2+1];
                bound[2]=jzdzb[i*2];
                bound[3]=jzdzb[i*2+1];
            }
            else{
                if(jzdzb[i*2]<bound[0])
                    bound[0]=jzdzb[i*2];
                else if(jzdzb[i*2]>bound[2])
                    bound[2]=jzdzb[i*2];
                if(jzdzb[i*2+1]<bound[1])
                    bound[1]=jzdzb[i*2+1];
                else if(jzdzb[i*2+1]>bound[3])
                    bound[3]=jzdzb[i*2+1];
            }
        }
        Boolean needdrop=false;//距离过近的如果上一点不能抛弃，needdrop为true，抛弃下一点
        for(int i=0;i<jzdzb.length;i+=2)
        {
            StringBuilder zb=new StringBuilder();
            zb.append(jzdzb[i].toString()+" "+jzdzb[i+1].toString());
            if(needdrop){
                needdrop=false;
                if(jzdzb[i]==bound[0]||jzdzb[i]==bound[2]||jzdzb[i+1]==bound[1]||jzdzb[i+1]==bound[3]){
                    values.add(zb.toString());
                }
                else{
                    jzdcount--;
                }
            }
            else if(jzdcount>4) {
                if (i == 0) {
                    if (!needDrop(jzdzb[i], jzdzb[i + 1], jzdzb[i + 2], jzdzb[i + 3], jzdzb[jzdzb.length - 2], jzdzb[jzdzb.length - 1])) {
                        if (!needDrop(jzdzb[i], jzdzb[i + 1], jzdzb[i + 2], jzdzb[i + 3]))
                            values.add(zb.toString());
                        else if(jzdzb[i]==bound[0]||jzdzb[i]==bound[2]||jzdzb[i+1]==bound[1]||jzdzb[i+1]==bound[3]){
                            needdrop=true;
                            values.add(zb.toString());
                        }
                        else
                            jzdcount--;
                    } else
                        jzdcount--;
                } else if (i == jzdzb.length - 2) {
                    if (!needDrop(jzdzb[jzdzb.length - 2], jzdzb[jzdzb.length - 1], jzdzb[0], jzdzb[1], jzdzb[jzdzb.length - 4], jzdzb[jzdzb.length - 3])) {
                        if (!needDrop(jzdzb[i], jzdzb[i + 1], jzdzb[0], jzdzb[1]))
                            values.add(zb.toString());
                        else if(jzdzb[i]==bound[0]||jzdzb[i]==bound[2]||jzdzb[i+1]==bound[1]||jzdzb[i+1]==bound[3]){
                            values.add(zb.toString());
                        }
                        else
                            jzdcount--;
                    } else
                        jzdcount--;
                } else {
                    if (!needDrop(jzdzb[i], jzdzb[i + 1], jzdzb[i - 2], jzdzb[i - 1], jzdzb[i + 2], jzdzb[i + 3])) {
                        if (!needDrop(jzdzb[i], jzdzb[i + 1], jzdzb[i + 2], jzdzb[i + 3]))
                            values.add(zb.toString());
                        else if(jzdzb[i]==bound[0]||jzdzb[i]==bound[2]||jzdzb[i+1]==bound[1]||jzdzb[i+1]==bound[3]){
                            needdrop=true;
                            values.add(zb.toString());
                        }
                        else
                            jzdcount--;
                    } else
                        jzdcount--;
                }
            }
            else
                values.add(zb.toString());
        }
        return values;
    }

    /**
     * 根据两条边的夹角判断是否要舍去两边交点
     * @param po_x 交点x坐标
     * @param po_y 交点y坐标
     * @param ps_x 起点x坐标
     * @param ps_y 起点y坐标
     * @param pe_x 终点x坐标
     * @param pe_y 终点y坐标
     * @return
     */
    private static boolean needDrop(Double po_x,Double po_y,Double ps_x,Double ps_y,Double pe_x,Double pe_y)
    {
        boolean value = false;
        Double jdrc = 30.0;//角度容差
        Double cosfi = 0.0;
        Double fi = 0.0;
        Double norm = 0.0;
        Double dsx = ps_x - po_x;
        Double dsy = ps_y - po_y;
        Double dex = pe_x - po_x;
        Double dey = pe_y - po_y;
        Double angle = 0.0;
        cosfi = dsx * dex + dsy * dey;
        norm = (dsx * dsx + dsy * dsy) * (dex * dex + dey * dey);
        cosfi /= Math.sqrt(norm);
        if(cosfi>=1.0) angle = 0.0;
        if(cosfi<=-1.0) angle = Math.PI;
        fi = Math.acos(cosfi);
        if (180 * fi / Math.PI < 180) {
            angle= 180 * fi / Math.PI;
        } else {
            angle= 360 - 180 * fi / Math.PI;
        }
        if(angle>180-jdrc) value = true;
        return  value;
    }

    /**
     * 根据两个相邻点间距离判断是否要舍去一个点
     * @param ps_x 起点x坐标
     * @param ps_y 起点y坐标
     * @param pe_x 终点x坐标
     * @param pe_y 终点y坐标
     * @return
     */
    private static boolean needDrop(Double ps_x,Double ps_y,Double pe_x,Double pe_y)
    {
        boolean value = false;
        Double jlrc = 0.0001;//距离容差
        if(Math.sqrt((ps_x-pe_x)*(ps_x-pe_x)+(ps_y-pe_y)*(ps_y-pe_y))<jlrc)
            value = true;
        return value;
    }

    /**
     * 获取四至节点
     * @param coors
     * @return
     */
    public static int[] getSZJDindex(vector[] coors)
    {
        Double[] rangle = getRotateAngle(coors);
        int[] indexs = new int[4];
        vector cpoint = getCenterPoint(coors);
        vector[] rcoors = new vector[coors.length];
        vector[] minRectangle = new vector[4];
        Double minarea = 0.0;
        Double minangle = 0.0;
        for (int ai = 0; ai < rangle.length; ai++)
        {
            for (int i = 0; i < coors.length; i++)
            {
                rcoors[i] = rotatePoint(coors[i], cpoint, rangle[ai]);
            }
            vector[] tempRectangle = getRectangle(rcoors);
            Double temparea = (tempRectangle[0].x - tempRectangle[2].x) * (tempRectangle[0].y - tempRectangle[2].y);
            if (minarea == 0)
            {
                minarea = temparea;
                minangle = rangle[ai];
                minRectangle = tempRectangle;
            }
            else
            {
                if (minarea > temparea)
                {
                    minarea = temparea;
                    minangle = rangle[ai];
                    minRectangle = tempRectangle;
                }
            }
        }
        for (int f = 0; f < minRectangle.length; f++)
            minRectangle[f] = rotatePoint(minRectangle[f], cpoint, -minangle);
        minRectangle = getSZPX(minRectangle);
        for (int i = 0; i < 4; i++)
        {
            indexs[i] = getNearestPointIndex(coors, minRectangle[i]);
        }
        return indexs;
    }

    /**
     * 按照北至、东至、南至、西至的顺序给节点排序
     * @param minRectangle
     * @return
     */
    private static vector[] getSZPX(vector[] minRectangle)
    {
        vector[] val = new vector[4];
        int ni = 0, wni = 0, wi = 3, ei = 1;
        Double maxy = minRectangle[0].y;
        for(int i=1;i<4;i++)
        {
            if (maxy < minRectangle[i].y)
            {
                maxy = minRectangle[i].y;
                ni = i;
                wi = ni - 1;
                ei = ni + 1;
            }
        }
        if (ei == 4) ei = 0;
        if (minRectangle[ei].y > minRectangle[wi].y)
            wni = ni;
        else if (minRectangle[ei].y < minRectangle[wi].y)
            wni = wi;
        else
        {
            if ((minRectangle[ei].x - minRectangle[ni].x) > (minRectangle[ni].x - minRectangle[wi].x))
            {
                wni = ni;
            }
            else
            {
                wni = wi;
            }
        }
        for(int i=0;i<4;i++)
        {
            int tempi = i + wni;
            if (tempi > 3) tempi = tempi - 4;
            val[i] = minRectangle[tempi];
        }
        return val;
    }

    /**
     * 获取坐标串中距已知点最近的点的索引
     * @param coors
     * @param pnt
     * @return
     */
    private static int getNearestPointIndex(vector[] coors, vector pnt)
    {
        int val = 0;
        Double neardist = getDist(coors[0], pnt);
        for (int i = 1; i < coors.length; i++)
        {
            Double tempdist = getDist(coors[i], pnt);
            if(tempdist<neardist)
            {
                neardist = tempdist;
                val = i;
            }
        }
        return val;
    }

    /**
     * 获取两点间距离
     * @param vector
     * @param pnt
     * @return
     */
    private static Double getDist(vector vector, vector pnt)
    {
        Double val = Math.sqrt((vector.x - pnt.x) * (vector.x - pnt.x) + (vector.y - pnt.y) * (vector.y - pnt.y));
        return val;
    }

    /**
     * 求简单外接矩形
     * @param rcoors
     * @return
     */
    private static vector[] getRectangle(vector[] rcoors)
    {
        vector[] val = new vector[4];
        int size = rcoors.length;
        if (size != 0)
        {
            Double Xmax = rcoors[0].x;
            Double Ymax = rcoors[0].y;
            Double Xmin = rcoors[0].x;  //最小值不能初始为0，
            Double Ymin = rcoors[0].y;  //最小值不能初始为0，
            for (int i = 0; i < size; i++)
            {
                Double tempx = rcoors[i].x;
                Double tempy = rcoors[i].y;
                if (tempx >= Xmax) Xmax = tempx;  //最大x，
                if (tempy >= Ymax) Ymax = tempy;  //最大y，
                if (tempx <= Xmin) Xmin = tempx;  //最小x
                if (tempy <= Ymin) Ymin = tempy;  //最小y
            }
            val[0] = new vector(Xmax, Ymax);  //右上
            val[1] = new vector(Xmax, Ymin);
            val[2] = new vector(Xmin, Ymin);
            val[3] = new vector(Xmin, Ymax);
        }
        return val;
    }

    /**
     * 获取多边形中心，所有节点坐标平均数
     * @param coors
     * @return
     */
    private static vector getCenterPoint(vector[] coors)
    {
        Double tempX, tempY;
        Double sumX = 0.0;
        Double sumY = 0.0;
        int size = coors.length;
        for (int i = 0; i < size; i++)
        {
            sumX = sumX + coors[i].x;
            sumY = sumY + coors[i].y;
        }
        tempX = sumX / size;
        tempY = sumY / size;
        vector pt = new vector(tempX, tempY);
        return pt;
    }

    /**
     * 某一点pt绕center旋转theta角度，zf,0706
     * @param pt
     * @param center
     * @param Q
     * @return
     */
    static vector rotatePoint(vector pt, vector center, Double Q)
    {
        Double x1 = pt.x;
        Double y1 = pt.y;
        Double x0 = center.x;
        Double y0 = center.y;

        //Double Q = theta / 180 * Math.PI;  //角度

        Double x2, y2;
        x2 = (x1 - x0) * Math.cos(Q) - (y1 - y0) * Math.sin(Q) + x0;   //旋转公式
        y2 = (x1 - x0) * Math.sin(Q) + (y1 - y0) * Math.cos(Q) + y0;

        vector rotatePoint = new vector(x2, y2);
        return rotatePoint;
    }

    /**
     * 获取旋转角度数组
     * @param coors
     * @return
     */
    private static Double[] getRotateAngle(vector[] coors)
    {
        List<Double> rangle = new ArrayList<Double>();
        //查找最北节点
        int npointindex = 0;
        for (int i = 1; i < coors.length; i++)
        {
            if (coors[i].y > coors[npointindex].y)
                npointindex = i;
        }
        //以最北节点为起始点查找多边形的凸多边形边，将其于x轴夹角作为旋转角度，角度不超过90°
        int pindex = npointindex;
        int nindex = npointindex + 1;
        for (int i = 0; i < coors.length; i++)
        {
            if(nindex>=coors.length)
            {
                nindex = nindex - coors.length;
            }
            if(AtOneSide(coors[pindex],coors[nindex],coors))
            {
                rangle.add(getAngel(coors[pindex], coors[nindex]));
                pindex = nindex;
            }
            nindex++;
        }
        Double[] dr=new Double[rangle.size()];
        rangle.toArray(dr);
        return dr;
    }

    /**
     * 获取线段与x轴夹角（角度不超过90°）
     * @param vector1
     * @param vector2
     * @return
     */
    private static Double getAngel(vector vector1, vector vector2)
    {
        Double val = Math.atan(Math.abs((vector1.y - vector2.y) / (vector1.x - vector2.x)));
        return val;
    }

    /**
     * 判断所有点是否在两点连线一侧
     * @param l1
     * @param l2
     * @param list
     * @return
     */
    private static boolean AtOneSide(vector l1, vector l2, vector[] list)
    {
        Double k = (l1.y - l2.y) / (l1.x - l2.x);
        Double b = l1.y - l1.x * (l1.y - l2.y) / (l1.x - l2.x);
        boolean v = GetV(l1, l2, k, b, list);
        for(vector l : list)
        {
            if (!l.equals(l1) && !l.equals(l2))
            {
                if ((l.y > (k * l.x + b)) != v)
                    return false;
            }
        }
        return true;
    }

    /**
     * 点集中随便找到第三点，确定他在两点连线的哪一侧
     * @param l1
     * @param l2
     * @param k
     * @param b
     * @param list
     * @return
     */
    private static Boolean GetV(vector l1, vector l2, Double k, Double b, vector[] list)
    {
        for (vector l : list)
        {
            if (!l.equals(l1) && !l.equals(l2))
            {
                return l.y > (k * l.x + b);
            }
        }
        return false;
    }
    public static void main(String[] args) {
        try {
            List<String> cszb=new ArrayList<>();
            cszb.add("38.601469976 77.1901106240001");
            cszb.add("38.600622554 77.1918553290001");
            cszb.add("38.5997585700001 77.1913048070001");
            cszb.add("38.599244985 77.1922440850001");
            cszb.add("38.5992313960001 77.1921625260001");
            cszb.add("38.5992409080001 77.1921391910001");
            cszb.add("38.5993383570001 77.1920164200001");
            cszb.add("38.5994051370001 77.191926198");
            cszb.add("38.599679671 77.1914185030001");
            cszb.add("38.599931858 77.190928946");
            cszb.add("38.5999517920001 77.1908891250001");
            cszb.add("38.6002599980001 77.1911683160001");
            cszb.add("38.6004613210001 77.190729961");
            cszb.add("38.601605104 77.1885418480001");
            cszb.add("38.601628137 77.188502542");
            cszb.add("38.6016460230001 77.18848224");
            cszb.add("38.601669057 77.1884701980001");
            cszb.add("38.6016681180001 77.188475166");
            cszb.add("38.6016659740001 77.188497678");
            cszb.add("38.6016654100001 77.188527019");
            cszb.add("38.6016673900001 77.1885915350001");
            cszb.add("38.601668374 77.188622814");
            cszb.add("38.6016723000001 77.1886354820001");
            cszb.add("38.601680128 77.1886578850001");
            cszb.add("38.60168486 77.1886764100001");
            cszb.add("38.6016903610001 77.1886949290001");
            cszb.add("38.6016943380001 77.1887154180001");
            cszb.add("38.6016990520001 77.1887310100001");
            cszb.add("38.6017030360001 77.188752477");
            cszb.add("38.6017040470001 77.1887876690001");
            cszb.add("38.6017050250001 77.188817971");
            cszb.add("38.6017045150001 77.1888551330001");
            cszb.add("38.6017017030001 77.1888923240001");
            cszb.add("38.601692773 77.188932515");
            cszb.add("38.6016853450001 77.188967802");
            cszb.add("38.6016782900001 77.1890162770001");
            cszb.add("38.6016687810001 77.1890582610001");
            cszb.add("38.601657577 77.1891054050001");
            cszb.add("38.601645245 77.1891562340001");
            cszb.add("38.6016390930001 77.189183487");
            cszb.add("38.601633006 77.18922029");
            cszb.add("38.6016285260001 77.1892394400001");
            cszb.add("38.601625352 77.1892806180001");
            cszb.add("38.601620042 77.1893460620001");
            cszb.add("38.6016186590001 77.1893960340001");
            cszb.add("38.6016154390001 77.1894306010001");
            cszb.add("38.6016082100001 77.1894688840001");
            cszb.add("38.6016054190001 77.1894821390001");
            cszb.add("38.6015963940001 77.1895108940001");
            cszb.add("38.6015823380001 77.189562477");
            cszb.add("38.6015596980001 77.189622974");
            cszb.add("38.601534933 77.1897099430001");
            cszb.add("38.601520964 77.1897740150001");
            cszb.add("38.6015016530001 77.1898991240001");
            cszb.add("38.601486171 77.1899948050001");
            cszb.add("38.6014727590001 77.1900559320001");
            System.out.println("old:");
            List<String> xcszb=getMainjzdbyDrop(cszb);
            for (int i = 0; i < xcszb.size(); i++) {
                System.out.println(xcszb.get(i));
            }
            System.out.println("new:");
            List<String> xcszb1=getMainjzd(cszb);
            for (int i = 0; i < xcszb1.size(); i++) {
                System.out.println(xcszb1.get(i));
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}
